/**
 * 解析成JSON对象的 parse()
 * --第一个参数是需要解析处理的JSON字符串
 * --第二个参数是可选参数提供可选的reviver函数，用在返回之前对所得到的对象执行变换操作
 * 
 * 
 * 对象或值转换为JSON字符串方法的 stringify()
 * --第一个参数传入的是要转换的对象；
 * --第二个是一个replacer函数，比如指定的replacer是数组，则可选择性地仅处理包含数组指定的属性；
 * --第三个参数用来控制结果字符串里面的间距，后面两个参数整体用得比较少。
 * 基础类型：
 *    undefined —— undefined
 *    symbol —— undefined
 *    string —— 不变
 *    boolean —— 字符型的布尔值
 *    number  —— 字符型数值
 *    null  —— 字符 “null”
 *    NaN和Infinity  —— “null”
 * 引用类型：
 *    数组 —— string
 *        undefined，function，symbol —— "null"
 *    function —— undefined
 *    RegExp —— “{}”
 *    Date —— Date的toJSON()字符串值
 *    普通object —— 
 *        --toJSON的返回值。
 *        --出现undefined，函数，或symbol的属性值，直接忽略。
 *        --以symbol为属性键的属性被忽略
 * 
 * 
 */
function jsonStringify(data) {
  let type = typeof data
  if (type !== 'object') {
    // 基础类型，string，number，boolean
    if (Number.isNaN(data) || data === Infinity) {
      return "null"
    } else if (type === 'string') {
      return `"${data}"`
    } else if (type === 'undefined' || type === 'function' || type === 'symbol') {
      return undefined
    } else {
      return String(data)
    }
  } else {
    // 引用类型
    if (data === null) {
      return "null"
    } else if (data.toJSON && typeof data.toJSON === 'function') {
      return jsonStringify(data.toJSON());
    } else if (data instanceof RegExp) {
      return "{}"
    } else if (data instanceof Date) {
      return data.toJSON
    } else if (Array.isArray(data)) {
      // 数组,遍历的处理
      let result = []
      data.forEach((item, index) => {
        if (typeof item === 'undefined' || typeof item === "function" || typeof item === "symbol") {
          result[index] = "null"
        } else {
          result[index] = jsonStringify(item)
        }
      });
      return (`[${result}]`).replace(/'/g, '"');
    } else {
      let result = []
      // 普通object
      Object.keys(data).forEach(key => {
        if (typeof key !== 'symbol') {
          if (data[key] !== undefined && typeof data[key] !== 'function' && typeof data[key] !== 'symbol') {
            result.push('"' + key + '"' + ":" + jsonStringify(data[key]));
          }
        }
      });
      return ("{" + result + "}").replace(/'/g, '"');


    }
  }

}

// let nl = null;
// console.log(jsonStringify(nl) === JSON.stringify(nl));
// true
// let und = undefined;
// console.log(jsonStringify(undefined) === JSON.stringify(undefined));
// // true
// let boo = false;
// console.log(jsonStringify(boo) === JSON.stringify(boo));
// // true
// let nan = NaN;
// console.log(jsonStringify(nan) === JSON.stringify(nan));
// // true
// let inf = Infinity;
// console.log(jsonStringify(Infinity) === JSON.stringify(Infinity));
// // true
// let str = "jack";
// console.log(jsonStringify(str) === JSON.stringify(str));
// // true
// let reg = new RegExp("\w");
// console.log(jsonStringify(reg) === JSON.stringify(reg));
// // true
// let date = new Date();
// console.log(jsonStringify(date) === JSON.stringify(date));
// // true
// let sym = Symbol(1);
// console.log(jsonStringify(sym) === JSON.stringify(sym));
// // true
// let array = [1,2,3];
// console.log(jsonStringify(array) === JSON.stringify(array));
// // true
let obj = {
  name: 'jack',
  age: 18,
  attr: ['coding', 123],
  date: new Date(),
  uni: Symbol(2),
  sayHi: function () {
    console.log("hi")
  },
  info: {
    sister: 'lily',
    age: 16,
    intro: {
      money: undefined,
      job: null
    }
  }
}
console.log(jsonStringify(obj) === JSON.stringify(obj));
// true